package com.gmstu.springorm.framework;

import com.gmstu.springorm.common.jdbc.BaseDao;
import com.gmstu.springorm.common.utils.GenericsUtils;
import com.gmstu.springorm.common.utils.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;
import java.util.List;
import java.util.Map;

/**
 * @author John.zhang
 * @version Id: BaseDaoSupport, v 1.0 2020/9/1 14:31 ZhiYong Exp $
 */

@Slf4j
public abstract class BaseDaoSupport<T, PK> implements BaseDao<T, PK> {

    private String tableName = "";

    private JdbcTemplate plateWrite;
    private JdbcTemplate jdbcTemplateRead;

    private DataSource dataSourceRead;
    private DataSource dataSourceWrite;

    private EntityOperation<T> entityOperation;


    public BaseDaoSupport() {
        try {
            Class<T> entityClass = GenericsUtils.getSuperClassGenericsType(getClass(), 0);
            entityOperation = new EntityOperation<T>(entityClass, this.getPKColumn());
            this.setTableName(entityOperation.tableName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected DataSource getDataSourceReadOnly() {
        return dataSourceRead;
    }

    protected DataSource getDataSourceWrite() {
        return dataSourceWrite;
    }

    protected void setDataSourceWrite(DataSource dataSourceWrite) {
        this.dataSourceWrite = dataSourceWrite;
        jdbcTemplateWrite = new JdbcTemplate(dataSourceWrite);
    }

    protected void setDataSourceRead(DataSource dataSourceRead) {
        this.dataSourceRead = dataSourceRead;
        jdbcTemplateRead = new JdbcTemplate(dataSourceRead);
    }

    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

    private JdbcTemplate jdbcTemplateReadOnly() {
        return this.jdbcTemplateRead;
    }

    private JdbcTemplate jdbcTemplateWrite() {
        return this.jdbcTemplateWrite;
    }


    @Override
    public List<T> select(QueryRule queryRule) throws Exception {
        QueryRuleSqlBuilder builder = new QueryRuleSqlBuilder(queryRule);
        String whereSql = removeFirstAnd(builder.getWhereSql());
        whereSql = "".equals(whereSql) ? whereSql : " where " + whereSql;
        String sql = "select " + entityOperation.allColumn + "from " + getTableName() + whereSql;
        Object[] values = builder.getValues();
        String orderSql = builder.getOrderSql();
        orderSql = StringUtils.isEmpty(orderSql) ? " " : (" order by " + orderSql);
        sql += orderSql;
        log.info(sql);
        return this.jdbcTemplateReadOnly().query(sql, this.entityOperation.rowMapper, values);
    }

    @Override
    public Page<T> select(QueryRule queryRule, int pageIndex, int pageSize) throws Exception {
        QueryRuleSqlBuilder builder = new QueryRuleSqlBuilder(queryRule);
        Object[] values = builder.getValues();
        String whereSql = removeFirstAnd(builder.getWhereSql());
        whereSql = ("".equals(whereSql) ? whereSql : " where " + whereSql);
        String countSql = "select count(1) from " + getTableName() + whereSql;
        long count = (Long) this.jdbcTemplateReadOnly().queryForMap(countSql, values).get("count(1)");
        if (count == 0) {
            return new Page<T>();
        }
        long start = (pageIndex - 1) * pageSize;
        String orderSql = builder.getOrderSql();
        orderSql = StringUtils.isEmpty(orderSql) ? " " : " order by " + orderSql;
        String sql = "select " + entityOperation.allColumn + " from " + getTableName() + whereSql + orderSql + " limit " + start + "," + pageSize;
        List<T> list = this.jdbcTemplateReadOnly().query(sql, this.entityOperation.rowMapper, values);
        log.info(sql);
        return new Page<T>(start, count, pageSize, list);
    }

    @Override
    public List<Map<String, Object>> selectBySql(String sql, Object... args) throws Exception {
        return this.jdbcTemplateRead.queryForList(sql, args);
    }

    @Override
    public Page<Map<String, Object>> selectBySqlToPage(String sql, Object[] param, int pageIndex, int pageSize) throws Exception {
        String countSql = "select count(1) from (" + sql + ") a";
        long count = (Long) this.jdbcTemplateRead.queryForMap(countSql, param).get("count(1)");
        if (count == 0) {
            return new Page<Map<String, Object>>();
        }

        long start = (pageIndex - 1) * pageSize;
        sql = sql + " limit " + start + "," + pageSize;
        List<Map<String, Object>> list = this.jdbcTemplateRead.queryForList(sql, pageIndex);
        return new Page<Map<String, Object>>(start, count, pageSize, list);
    }

    @Override
    public boolean deleteAll(List<T> list) throws Exception {
        return false;
    }

    @Override
    public PK insert(T entity) throws Exception {
        return null;
    }

    @Override
    public int insertAll(List<T> list) throws Exception {
        return 0;
    }

    @Override
    public boolean update(T entity) throws Exception {
        return false;
    }

    /**
     * 获取主键
     *
     * @return
     */
    protected abstract String getPKColumn();

    /**
     * 设置数据源
     *
     * @param dataSource
     */
    protected abstract void setDataSource(DataSource dataSource);

    private String removeFirstAnd(String sql) {
        if (StringUtils.isEmpty(sql)) {
            return sql;
        }
        return sql.trim().toLowerCase().replaceAll("\\s*and", "") + " ";
    }
}
